<?php
/*
 * Copyright 2007 by Aleksander Adamowski
 * This software is licensed under GPL v.3.0.
 * See the included file "LICENSE" for details.
 * 
 * This script renders a HTML table with data of a single given person
 * taken from LDAP.
 * 
 * Can be included from other scripts.
 * 
 * Parameters accepted:
 *  - uid (mandatory): specifies the person by UID.
 *  - oper (optional): specifies the type of operation performed on LDAP data 
 *    (currently supported: "change_photo")
 */
if (!isset($included_uid)) {
	Header("Content-type: text/html; charset=UTF-8"); 
	require_once 'nocache.php';
}
require_once 'config.php';

$uid = $_SERVER['PHP_AUTH_USER'];
$bind_uid = $uid;
if (isset($_GET['uid'])) {
	$uid = $_GET['uid'];
}

// If we're being included from a different script, don't generate HTML headers
// and operate on the uid set by the including script:
if (isset($included_uid)) {
	$uid = $included_uid;
} else {
?>

<HTML>
<HEAD>
<TITLE> LDAP entry: (uid=<?php echo htmlspecialchars($uid); ?>) </TITLE>
<?php
require_once 'style.php';
?>
</HEAD>
<BODY>
<?php
}

$oper = isset($_GET['oper']) ? $_GET['oper'] : '';

// Defend against LDAP filter injection:
$uid = preg_replace('/[^-_a-zA-Z0-9]/', '', $uid);
$bind_uid = preg_replace('/[^-_a-zA-Z0-9]/', '', $bind_uid);

$RESIZE_THRESHOLD_FILE_SIZE=30;

$photo_present = 0;
$change_description = '';
if ($oper == 'change_photo') {
	$change_description = '';
	if (isset($_FILES['photo'])) {
#error_log("Size: ".$_FILES['photo']['size']);
		$file = $_FILES['photo'];
		if ($file['error'] == UPLOAD_ERR_OK) {
			$tmp_name = $file['tmp_name'];
			if ($file['size'] <= $RESIZE_THRESHOLD_FILE_SIZE*1024) {
				// Size OK, no need to do anything:
				$photo_present = 1;
				$change_description = 'photo';

			} elseif ($file['size'] <= $MAX_FILE_SIZE*1024) {
				echo "<H2>The jpeg file is too large. The threshold is $RESIZE_THRESHOLD_FILE_SIZE KB. Photo has been automatically scaled down.</H2>";
				$tmp_dir = dirname($tmp_name);
				list($width, $height, $type, $attr) = getimagesize($tmp_name);
				$jpeg_image = imagecreatefromjpeg($tmp_name);
				unlink($tmp_name);
				$aspect = $width / $height;
				// Protect against ultra-high or ultra-wide photos:
				if ($aspect < 0.2 || $aspect > 2.5) {
					$aspect = 0.66;
				}
				$tmp_name = $tmp_dir.'/'.md5(rand()).'.jpg';
				error_log("Aspect of $tmp_name [$width x $height]: $aspect. Name: $tmp_name");
				$new_jpeg_image = imagecreatetruecolor($IMAGE_STD_WIDTH, $IMAGE_STD_WIDTH / $aspect);
				imagecopyresampled($new_jpeg_image, $jpeg_image, 0, 0, 0, 0, $IMAGE_STD_WIDTH, $IMAGE_STD_WIDTH / $aspect, $width, $height);
				imagejpeg ($new_jpeg_image, $tmp_name);
				$photo_present = 1;
				$change_description = 'photo';
			} else {
				error_log("File $tmp_name too big: ".$file['size']);
				unlink($tmp_name);
				unset($tmp_name);
				echo "<H2 STYLE=\"color: red\">The jpeg file is too large. The limit is $MAX_FILE_SIZE KB. Photo rejected.</H2>";
			}
		}
	}
	$ds = ldap_connect($LDAP_SERVER);
	$bind_sr = ldap_search($ds, $LDAP_PEOPLE, "(uid=$bind_uid)", array('dn'));
	$bind_dn = ldap_get_dn($ds, ldap_first_entry($ds, $bind_sr));
	$sr = ldap_search($ds, $LDAP_PEOPLE,"(uid=$uid)", array('dn', 'jpegPhoto', 'mobile', 'telephoneNumber'));
	if (ldap_count_entries($ds, $sr) == 1) {
		$entry = ldap_first_entry($ds, $sr);
		if ($photo_present == 1) {
			$old_photo_data = ldap_get_values_len($ds, $entry, 'jpegPhoto');
			// Defend against filesystem traversal:
			$clean_uid = preg_replace('[^a-zA-Z0-9.]', '', $uid);
			$old_photo_file = tempnam(dirname(__FILE__).'/old/', "jpegPhoto_${clean_uid}_".date('Y-m-d_H_i_s').'_');
			rename($old_photo_file, $old_photo_file.'.jpg');
			$old_photo_file .= '.jpg';
			$filehandle_oldphoto = fopen($old_photo_file, 'w');
			fwrite($filehandle_oldphoto, $old_photo_data[0]);
			fclose($filehandle_oldphoto);
			error_log("Old photo file: $old_photo_file");
		}
		$dn = ldap_get_dn($ds, $entry);
		$attribs = ldap_get_attributes($ds, $entry);
		$newdata = '';
		$deldata = '';
		$ldapbind = ldap_bind($ds, $bind_dn, $_SERVER['PHP_AUTH_PW']);
		if ($ldapbind) {
			if ($photo_present) {
				$filehandle = fopen($tmp_name, 'r');
				if ($filehandle) {
					//while (!feof ($filehandle)) {
					// Read max. 4 MB:
					$newphoto = fread($filehandle,41951232);
					//}
					fclose ($filehandle);
					unlink($tmp_name);
					$newdata['jpegPhoto'] = $newphoto;
				}
			}
			if (isset($_POST['mobile'])) {
				if (!empty($_POST['mobile'])) {
					$newdata['mobile'] = $_POST['mobile'];
					$change_description = (strlen($change_description) > 0 ? "$change_description, mobile" : 'mobile');
				} else {
					if (isset($attribs['mobile'][0])) {
						$deldata['mobile'] = array();
						$change_description = (strlen($change_description) > 0 ? "$change_description, removes mobile" : 'removes mobile');
					}
				}
			}
			if (isset($_POST['telephoneNumber'])) {
				if (!empty($_POST['telephoneNumber'])) {
					$newdata['telephoneNumber'] = $_POST['telephoneNumber'];
					$change_description = (strlen($change_description) > 0 ? "$change_description, phone" : 'phone');
				} else {
					if (isset($attribs['telephoneNumber'][0])) {
						$deldata['telephoneNumber'] = array();
						$change_description = (strlen($change_description) > 0 ? "$change_description, removes phone" : 'removes phone');
					}
				}
			}
			if (isset($newdata) && $newdata != '') {
				// Some data has changed
				if ($bind_uid == $uid) {
					$notification_text = "The user $uid changes own $change_description in LDAP";
					error_log("$notification_text.");
					mail($ADMIN_EMAIL, "$notification_text",
							"$notification_text\r\n\r\n" .
							"See: \r\n" .
							"https://" . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . "?uid=$uid" .
							"\r\n",
							"From: $SENDER_EMAIL\r\n".
							'X-Mailer: PHP/' . phpversion() . "\r\n" .
							"MIME-Version: 1.0\r\n" .
							"Content-Type: text/plain; charset=utf-8\r\n" .
							"Content-Transfer-Encoding: 8bit\r\n"
							);
				} else {
					$notification_text = "The user $bind_uid changes $change_description of user $uid in LDAP";
					error_log("$notification_text.");
					mail($ADMIN_EMAIL, "$notification_text",
							"$notification_text\r\n\r\n" .
							"See: \r\n" .
							"https://" . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . "?uid=$uid" .
							"\r\n",
							"From: $SENDER_EMAIL\r\n".
							'X-Mailer: PHP/' . phpversion() . "\r\n" .
							"MIME-Version: 1.0\r\n" .
							"Content-Type: text/plain; charset=utf-8\r\n" .
							"Content-Transfer-Encoding: 8bit\r\n"
							);
				}
				error_log("Changed LDAP data:".var_export($newdata, TRUE));
				error_log("Deleted LDAP data:".var_export($deldata, TRUE));
				
				$collective_result = TRUE;
				$result = ldap_mod_replace($ds, $dn, $newdata);
				if (!$result) {
					$collective_result = FALSE;
				} elseif (is_array($deldata)) {
					$result = ldap_mod_del($ds, $dn, $deldata);
					if (!$result) {
						$collective_result = FALSE;
					}
				}
				if ($collective_result) {
					echo "<P>Data changed.</P>" ;
				} else {
					echo "<P>Problem changing data in LDAP.</P>" ;
				}
				// Let the change propagate in the cluster:
				sleep(3);
			}
		} else {
			echo "<H2>Binding to LDAP failed.</H2>";
		}
	} else {
		echo '<H2>Entry not found: '.htmlspecialchars($uid).'.</H2>';
	}
}

$ds = ldap_connect($LDAP_SERVER);
$sr = ldap_search($ds, $LDAP_PEOPLE,"(uid=$uid)", array(
			'dn',
			'cn', 
			'gn', 
			'sn', 
			'manager',
			'employeeType',
			'mail',
			'telephoneNumber',
			'userSMIMECertificate',
			'userCertificate',
			'mobile',
			'ou',
			'uid',
			'manager',
			'accountActive'));

if (ldap_count_entries($ds, $sr) == 1) {
	$entry = ldap_first_entry($ds, $sr);
	echo "<TABLE BORDERS=\"1\" STYLE=\"border-collapse: collapse;\">\n";

	$dn = ldap_get_dn($ds, $entry);
	$attribs = ldap_get_attributes($ds, $entry);
	$account_active = 1;
	#error_log('accountActive: '.$attribs['accountActive'][0]);
	if ($attribs['accountActive'][0] != 'TRUE') {
		echo '<TR><TH CLASS="ldapcell_inactive">Technical or inactive account.</TR>';
		$account_active = 0;
	}
	echo '<TR>';
	echo ($account_active ? '<TD CLASS="ldapcell_odd">' : '<TD CLASS="ldapcell_inactive">');
	echo '<H3>';
	echo (isset($included_uid)) ? "<A HREF=\"".basename(__FILE__)."?uid=".htmlspecialchars($uid)."\">".htmlspecialchars($attribs['cn'][0])."</A>" : htmlspecialchars($attribs['cn'][0]);
	echo '</H3>';
	echo '<P>';
	echo '<A HREF="mailto:'.htmlspecialchars($attribs['mail'][0]).'">';
	echo htmlspecialchars($attribs['mail'][0]);
	echo '</A>';
	echo '</P>';
	echo ($account_active ? '<TD CLASS="ldapcell_odd">' : '<TD CLASS="ldapcell_inactive">');
	echo '<B>uid:</B> ';
	echo htmlspecialchars($attribs['uid'][0]);
	echo "</TR>\n";

	echo '<TR>';
	echo ($account_active ? '<TD CLASS="ldapcell_even">' : '<TD CLASS="ldapcell_inactive">');
	echo '<P>';
	echo '<B>Position:</B> ';
	if (isset($attribs['employeeType'])) echo htmlspecialchars($attribs['employeeType'][0]);
	echo '</P>';
	if (isset($attribs['manager']) && isset($attribs['manager'][0])) {
		$manager = $attribs['manager'][0];
		//error_log("Searching for manager: $manager");
		$sr = ldap_search($ds, $manager, '(cn=*)', array('cn', 'uid'));
		if (ldap_errno($ds) != 0) {
			error_log("LDAP error when searching for $uid's manager ($manager) : ".ldap_error($ds));
		} else {
			$manager_entry = ldap_first_entry($ds, $sr);
			$manager_attribs = ldap_get_attributes($ds, $manager_entry);
			echo '<P>';
			echo ' <B>Manager:</B> ';
			if (isset($included_uid)) {
				$manager_uri = basename(__FILE__);
			} else {
				$request_uri = $_SERVER['REQUEST_URI'];
				$manager_uri = preg_replace ( '/uid\=[^&]+/', 'uid='.$manager_attribs['uid'][0], $request_uri);
			}
			if (! preg_match ('/uid\=[^&]+/', $manager_uri)) {
				if ( preg_match ('/\?/', $manager_uri)) {
					$manager_uri .= '&uid='.$manager_attribs['uid'][0];
				} else {
					$manager_uri .= '?uid='.$manager_attribs['uid'][0];
				}
				if ($manager_attribs['uid'][0] == $_SERVER['PHP_AUTH_USER']) {
					$manager_uri .= '&oper=change_photo';
				}
			}
			//error_log($manager_uri);
			echo '<A HREF="'.$manager_uri.'">';
			echo htmlspecialchars($manager_attribs['cn'][0]);
			echo '</A>';
			echo "</P>\n";
		}
	}
	if (isset ($attribs['telephoneNumber'])) {
		echo '<P>';
		echo '<B>Phone:</B> ';
		echo htmlspecialchars($attribs['telephoneNumber'][0]);
		echo '</P>';
	}
	if (isset ($attribs['mobile'])) {
		echo '<P>';
		echo '<B>Mobile:</B> ';
 		echo join('<br/>', array_map('htmlspecialchars',array_slice($attribs['mobile'], 1)));
		echo '</P>';
	}
	echo ($account_active ? '<TD CLASS="ldapcell_even">' : '<TD CLASS="ldapcell_inactive">');
	echo '<IMG SRC="ldap_photo.php?uid='.htmlspecialchars($uid).'"/>';
	echo "</TR>\n";


	echo '<TR>';
	echo ($account_active ? '<TD CLASS="ldapcell_odd">' : '<TD CLASS="ldapcell_inactive">');
	echo '<B>Organizational units:</B> ';
 	$ou_array = array_map('htmlspecialchars',array_slice($attribs['ou'], 1));
	$ou_array_processed = array();
	foreach ($ou_array as $ou) {
		array_push($ou_array_processed, "<A HREF=\"ldap_gallery.php?ou=$ou\">$ou</A>");
	}
	//echo implode(', ', array_slice($attribs['ou'], 1));
	echo implode(', ', $ou_array_processed);

	echo "</TR>\n";

	echo "<TR>\n";
	if (isset($attribs['userSMIMECertificate;binary']) ||
			isset($attribs['userSMIMECertificate']) ||
			isset($attribs['userCertificate;binary']) ||
			isset($attribs['userCertificate'])) {
		echo '<TD CLASS="ldapcell_even" COLSPAN="1">'.htmlspecialchars($dn).'</TD>';
		echo ($account_active ? '<TD CLASS="ldapcell_odd">' : '<TD CLASS="ldapcell_inactive">');
		echo '<A HREF="ldap_smimecert.php?uid='.htmlspecialchars($uid).'"><IMG SRC="cert.png" BORDER="0"/></A>';
	} else {
		echo '<TD CLASS="ldapcell_even" COLSPAN="2">'.htmlspecialchars($dn).'</TD>';
	}
	echo "</TR>\n";


	echo "</TABLE>\n";
}


//				<input type="hidden" name="MAX_FILE_SIZE" value="< ? php echo $MAX_FILE_SIZE*1024; ? >" />
if ($oper == 'change_photo' && ($_SERVER['PHP_AUTH_USER'] == $uid || $LDAP_PHOTO_ADMINS[$_SERVER['PHP_AUTH_USER']] == 1)) {
	?>

		<P>
		Submit new JPG photo (max. <?php echo $MAX_FILE_SIZE ?> KB): </P>
			<form enctype="multipart/form-data" action="" method="POST">
				<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $MAX_FILE_SIZE*1024; ?>" />
				<P><input name="photo" type="file" /> </P>
				<P>Phone: <input type="text" name="telephoneNumber" size="24" value="<?php echo (isset($attribs['telephoneNumber']) ? htmlspecialchars($attribs['telephoneNumber'][0]) : ''); ?>" /> </P>
				<P>Mobile: <input type="text" name="mobile" size="32" value="<?php echo (isset($attribs['mobile']) ? htmlspecialchars($attribs['mobile'][0]): ''); ?>" /> </P>
				<input type="submit" value="Change data" />
				</form>
				<?php
}
if (!isset($included_uid)) {
	?>

		</BODY>
		</HTML>
		<?php
}
?>
